import os
import json
import requests
from pathlib import Path
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.util import Pt, Inches
from pptx.dml.color import RGBColor
from pptx.enum.dml import MSO_COLOR_TYPE
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
import re
import logging
import time
import shutil
from copy import deepcopy

# 导入 Glossary 模块
from glossary_module import Glossary

# 设置日志
logger = logging.getLogger(__name__)

# ====== 默认字体配置 ======
DEFAULT_FONT_CONFIG = {
    'name': '宋体',  # 默认字体名称
    'size': Pt(14),  # 默认字体大小
    'color': RGBColor(0, 0, 0),  # 默认黑色
    'bold': False,
    'italic': False
}

# ====== 用户输入 ======
api_url = input("请输入 API URL: ").strip()
api_key = input("请输入 API Key: ").strip()
model_name = input("请输入模型名称（如 gpt-4、gpt-3.5-turbo）: ").strip()
source_lang = input("请输入源语言代码（如 zh-cn, en, fr），留空则自动检测: ").strip().lower()
target_lang = input("请输入目标语言代码（如 zh-cn, en, fr）: ").strip().lower()
glossary_csv_paths = input("请输入术语表 CSV 文件路径（多个文件用逗号分隔，可留空）: ").strip()

# 备份文件选项
create_backup = input("是否创建备份文件？(y/n，默认n): ").strip().lower() == 'y'

# 字体配置选项
print("\n=== 默认字体配置 ===")
use_default_font = input("是否使用默认字体设置？(y/n，默认n): ").strip().lower() == 'y'
if use_default_font:
    font_name = input(f"请输入默认字体名称（默认: {DEFAULT_FONT_CONFIG['name']}）: ").strip()
    if font_name:
        DEFAULT_FONT_CONFIG['name'] = font_name

    font_size = input("请输入默认字体大小（默认: 14）: ").strip()
    if font_size and font_size.isdigit():
        DEFAULT_FONT_CONFIG['size'] = Pt(int(font_size))

    print("默认字体配置已设置")
else:
    DEFAULT_FONT_CONFIG = None


def load_glossaries(paths_str, target_lang_out):
    """加载多个glossary文件"""
    loaded_glossaries = []

    if not paths_str:
        return loaded_glossaries

    paths_list = paths_str.split(",")
    for p_str in paths_list:
        file_path = Path(p_str.strip())

        if not file_path.exists():
            logger.error(f"Glossary file not found: {file_path}")
            print(f"警告：术语表文件不存在: {file_path}")
            continue

        if not file_path.is_file():
            logger.error(f"Glossary path is not a file: {file_path}")
            print(f"警告：术语表路径不是文件: {file_path}")
            continue

        try:
            glossary_obj = Glossary.from_csv(file_path, target_lang_out)
            if glossary_obj.entries:
                loaded_glossaries.append(glossary_obj)
                logger.info(f"Loaded glossary '{glossary_obj.name}' with {len(glossary_obj.entries)} entries.")
                print(f"成功加载术语表 '{glossary_obj.name}'，包含 {len(glossary_obj.entries)} 条术语")
            else:
                logger.info(
                    f"Glossary '{file_path.stem}' loaded with no applicable entries for lang_out '{target_lang_out}'.")
                print(f"术语表 '{file_path.stem}' 已加载但没有适用于目标语言 '{target_lang_out}' 的术语")

        except Exception as e:
            logger.error(f"Failed to load glossary from {file_path}: {e}")
            print(f"错误：加载术语表失败 {file_path}: {e}")

    return loaded_glossaries


# 加载所有glossary
glossaries = load_glossaries(glossary_csv_paths, target_lang)
print(f"总共加载了 {len(glossaries)} 个术语表")


def apply_glossary_translations(text, glossaries_list):
    """应用术语表翻译"""
    if not text or not glossaries_list:
        return text

    modified_text = text
    all_matches = []

    for glossary in glossaries_list:
        matches = glossary.get_active_entries_for_text(text)
        if matches:
            all_matches.extend(matches)

    if not all_matches:
        return text

    all_matches = sorted(set(all_matches), key=lambda x: len(x[0]), reverse=True)
    replacement_count = 0

    for source_term, target_term in all_matches:
        if source_term in modified_text:
            if re.search(r'\b' + re.escape(source_term) + r'\b', modified_text, re.IGNORECASE):
                modified_text = re.sub(
                    r'\b' + re.escape(source_term) + r'\b',
                    target_term,
                    modified_text,
                    flags=re.IGNORECASE
                )
                replacement_count += 1
            elif not re.search(r'[a-zA-Z]', source_term):
                modified_text = modified_text.replace(source_term, target_term)
                replacement_count += 1

    return modified_text


def call_custom_api(text):
    """调用翻译API，带重试机制"""
    max_retries = 3
    retry_delay = 2

    source_name = {"zh-cn": "Chinese", "en": "English", "fr": "French", "ja": "Japanese", "de": "German"}.get(
        source_lang, source_lang)
    target_name = {"zh-cn": "Chinese", "en": "English", "fr": "French", "ja": "Japanese", "de": "German"}.get(
        target_lang, target_lang)

    glossary_info = ""
    if glossaries:
        relevant_terms = []
        for glossary in glossaries:
            matches = glossary.get_active_entries_for_text(text)
            relevant_terms.extend(matches)

        if relevant_terms:
            unique_terms = list(set(relevant_terms))
            term_list = "\n".join([f"- {src} → {tgt}" for src, tgt in unique_terms[:10]])
            glossary_info = f"""

IMPORTANT TERMINOLOGY:
Please use these specific translations for the following terms:
{term_list}
"""

    prompt = f"""Translate the following text from {source_name} to {target_name}.{glossary_info}

IMPORTANT RULES:
1. Only return the translated text, no explanations or additional content
2. If the text is empty or contains only spaces/punctuation, return it as-is
3. Preserve original formatting and line breaks
4. Do not add phrases like "Here is the translation:" or "翻译结果："
5. Maintain the same tone and style as the original
6. Follow the terminology guidelines provided above strictly

Text to translate:
{text}"""

    payload = {
        "model": model_name,
        "messages": [
            {"role": "system",
             "content": "You are a professional translator. Only return the direct translation without any additional commentary or formatting."},
            {"role": "user", "content": prompt},
        ],
        "temperature": 0.1,
        "max_tokens": len(text) * 3 + 100
    }

    headers = {
        "Accept": "application/json",
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }

    for attempt in range(max_retries):
        try:
            response = requests.post(api_url, headers=headers, json=payload, timeout=60)
            response.raise_for_status()
            data = response.json()
            translated = data["choices"][0]["message"]["content"].strip()

            unwanted_prefixes = [
                "翻译结果：", "以下是翻译结果：", "翻译：", "Translation:", "Here is the translation:",
                "The translation is:", "Translated text:", "翻译内容：", "译文：", "翻译后："
            ]

            for prefix in unwanted_prefixes:
                if translated.startswith(prefix):
                    translated = translated[len(prefix):].strip()

            return translated

        except Exception as e:
            if attempt < max_retries - 1:
                print(f"API调用失败，第{attempt + 1}次重试... 错误：{str(e)}")
                time.sleep(retry_delay)
                retry_delay *= 2
            else:
                raise e


def should_translate(text):
    """判断文本是否需要翻译"""
    if not text or not text.strip():
        return False

    if re.match(r'^[\s\d\W]*$', text):
        return False

    clean_text = re.sub(r'[\s\W]', '', text)
    if len(clean_text) < 2:
        return False

    return True


def translate_text(text):
    """翻译文本"""
    if not should_translate(text):
        return text

    original_text = text

    try:
        text_with_glossary = apply_glossary_translations(text, glossaries)
        translated = call_custom_api(text)
        final_translation = apply_glossary_translations(translated, glossaries)

        if len(final_translation) > len(original_text) * 5:
            print(f"警告：翻译结果异常长，保持原文：{original_text[:50]}...")
            return original_text

        if any(phrase in final_translation.lower() for phrase in [
            "i'm sorry", "i cannot", "please provide", "you have not provided",
            "could you please", "it seems like", "no text to translate"
        ]):
            print(f"警告：检测到错误翻译，保持原文：{original_text[:50]}...")
            return original_text

        return final_translation

    except Exception as e:
        print(f"翻译失败，保持原文：{original_text[:50]}... 错误：{str(e)}")
        return original_text


# ====== 完整的颜色处理函数 ======
def comprehensive_get_color_info(font):
    """全面获取颜色信息 - 覆盖所有颜色类型"""
    try:
        color_info = {
            'type': None,
            'rgb_value': None,
            'theme_color': None,
            'brightness': None,
            'color_type': None
        }

        if hasattr(font, 'color') and font.color is not None:
            # 获取颜色类型
            if hasattr(font.color, 'type'):
                color_info['color_type'] = font.color.type

                if font.color.type == MSO_COLOR_TYPE.RGB:
                    color_info['type'] = 'rgb'
                    if hasattr(font.color, 'rgb') and font.color.rgb is not None:
                        color_info['rgb_value'] = font.color.rgb

                elif font.color.type == MSO_COLOR_TYPE.THEME:
                    color_info['type'] = 'theme'
                    if hasattr(font.color, 'theme_color'):
                        color_info['theme_color'] = font.color.theme_color
                    # 获取主题色的亮度调整
                    if hasattr(font.color, 'brightness'):
                        color_info['brightness'] = font.color.brightness

                elif font.color.type == MSO_COLOR_TYPE.SCHEME:
                    color_info['type'] = 'scheme'

                elif font.color.type == MSO_COLOR_TYPE.HSL:
                    color_info['type'] = 'hsl'

                else:  # AUTO or other types
                    color_info['type'] = 'auto'

            # 备用方法：直接尝试获取RGB值
            if not color_info['rgb_value']:
                try:
                    if hasattr(font.color, 'rgb') and font.color.rgb is not None:
                        color_info['rgb_value'] = font.color.rgb
                        if not color_info['type']:
                            color_info['type'] = 'rgb'
                except:
                    pass

        # 如果都获取不到，可能是继承的颜色
        if not color_info['type']:
            color_info['type'] = 'inherited'

        return color_info

    except Exception as e:
        logger.debug(f"Error getting comprehensive color info: {e}")
        return {'type': 'inherited', 'rgb_value': None, 'theme_color': None, 'brightness': None}


def comprehensive_set_color_info(font, color_info):
    """全面设置颜色信息 - 支持所有颜色类型"""
    try:
        if not color_info:
            return

        color_type = color_info.get('type')

        if color_type == 'rgb' and color_info.get('rgb_value'):
            font.color.rgb = color_info['rgb_value']

        elif color_type == 'theme' and color_info.get('theme_color') is not None:
            font.color.theme_color = color_info['theme_color']
            # 设置亮度调整
            if color_info.get('brightness') is not None:
                try:
                    font.color.brightness = color_info['brightness']
                except:
                    pass

        elif color_type == 'inherited':
            # 继承的颜色不做处理，保持原有继承关系
            return

        elif color_type == 'auto':
            # 自动颜色，尝试不设置让系统自动处理
            return

        else:
            # 其他情况，如果有RGB值就使用RGB值
            if color_info.get('rgb_value'):
                font.color.rgb = color_info['rgb_value']
            else:
                # 最后才使用默认颜色，避免改变原有的白色等颜色
                if DEFAULT_FONT_CONFIG and use_default_font:
                    font.color.rgb = DEFAULT_FONT_CONFIG['color']

    except Exception as e:
        logger.debug(f"Error setting comprehensive color info: {e}")


# ====== 完整的段落格式处理 ======
def get_paragraph_format(paragraph):
    """获取段落格式信息"""
    try:
        para_format = {}

        # 对齐方式
        if hasattr(paragraph, 'alignment') and paragraph.alignment is not None:
            para_format['alignment'] = paragraph.alignment

        # 段落级别（用于列表等）
        if hasattr(paragraph, 'level') and paragraph.level is not None:
            para_format['level'] = paragraph.level

        # 行间距
        if hasattr(paragraph, 'line_spacing') and paragraph.line_spacing is not None:
            para_format['line_spacing'] = paragraph.line_spacing

        # 段前段后间距
        if hasattr(paragraph, 'space_before') and paragraph.space_before is not None:
            para_format['space_before'] = paragraph.space_before
        if hasattr(paragraph, 'space_after') and paragraph.space_after is not None:
            para_format['space_after'] = paragraph.space_after

        return para_format

    except Exception as e:
        logger.debug(f"Error getting paragraph format: {e}")
        return {}


def set_paragraph_format(paragraph, para_format):
    """设置段落格式"""
    try:
        if not para_format:
            return

        # 设置对齐方式
        if 'alignment' in para_format:
            try:
                paragraph.alignment = para_format['alignment']
            except Exception as e:
                logger.debug(f"Error setting alignment: {e}")

        # 设置段落级别
        if 'level' in para_format:
            try:
                paragraph.level = para_format['level']
            except Exception as e:
                logger.debug(f"Error setting level: {e}")

        # 设置行间距
        if 'line_spacing' in para_format:
            try:
                paragraph.line_spacing = para_format['line_spacing']
            except Exception as e:
                logger.debug(f"Error setting line_spacing: {e}")

        # 设置段前段后间距
        if 'space_before' in para_format:
            try:
                paragraph.space_before = para_format['space_before']
            except Exception as e:
                logger.debug(f"Error setting space_before: {e}")

        if 'space_after' in para_format:
            try:
                paragraph.space_after = para_format['space_after']
            except Exception as e:
                logger.debug(f"Error setting space_after: {e}")

    except Exception as e:
        logger.debug(f"Error setting paragraph format: {e}")


# ====== 形状级格式处理 ======
def get_text_frame_format(text_frame):
    """获取文本框级别的格式"""
    try:
        frame_format = {}

        # 文本框的对齐方式
        if hasattr(text_frame, 'vertical_anchor') and text_frame.vertical_anchor is not None:
            frame_format['vertical_anchor'] = text_frame.vertical_anchor

        # 文本框的边距
        if hasattr(text_frame, 'margin_left') and text_frame.margin_left is not None:
            frame_format['margin_left'] = text_frame.margin_left
        if hasattr(text_frame, 'margin_right') and text_frame.margin_right is not None:
            frame_format['margin_right'] = text_frame.margin_right
        if hasattr(text_frame, 'margin_top') and text_frame.margin_top is not None:
            frame_format['margin_top'] = text_frame.margin_top
        if hasattr(text_frame, 'margin_bottom') and text_frame.margin_bottom is not None:
            frame_format['margin_bottom'] = text_frame.margin_bottom

        # 文字换行方式
        if hasattr(text_frame, 'word_wrap') and text_frame.word_wrap is not None:
            frame_format['word_wrap'] = text_frame.word_wrap

        return frame_format

    except Exception as e:
        logger.debug(f"Error getting text frame format: {e}")
        return {}


def set_text_frame_format(text_frame, frame_format):
    """设置文本框格式"""
    try:
        if not frame_format:
            return

        # 设置垂直对齐
        if 'vertical_anchor' in frame_format:
            try:
                text_frame.vertical_anchor = frame_format['vertical_anchor']
            except Exception as e:
                logger.debug(f"Error setting vertical_anchor: {e}")

        # 设置边距
        for margin_attr in ['margin_left', 'margin_right', 'margin_top', 'margin_bottom']:
            if margin_attr in frame_format:
                try:
                    setattr(text_frame, margin_attr, frame_format[margin_attr])
                except Exception as e:
                    logger.debug(f"Error setting {margin_attr}: {e}")

        # 设置换行方式
        if 'word_wrap' in frame_format:
            try:
                text_frame.word_wrap = frame_format['word_wrap']
            except Exception as e:
                logger.debug(f"Error setting word_wrap: {e}")

    except Exception as e:
        logger.debug(f"Error setting text frame format: {e}")


# ====== 非破坏性文本翻译函数 ======
def non_destructive_translate_text_frame(text_frame):
    """非破坏性翻译文本框 - 保持所有格式层级"""
    try:
        # 检查是否有需要翻译的文本
        if not text_frame or not hasattr(text_frame, 'text'):
            return False

        full_text = text_frame.text.strip()
        if not should_translate(full_text):
            return False

        print(f"    翻译文本: {full_text[:50]}...")

        # 1. 保存文本框级别的格式
        frame_format = get_text_frame_format(text_frame)

        # 2. 遍历每个段落进行非破坏性更新
        translated_paragraphs = []

        for paragraph in text_frame.paragraphs:
            # 保存段落格式
            para_format = get_paragraph_format(paragraph)

            # 收集并翻译该段落的所有run
            translated_runs = []
            for run in paragraph.runs:
                if not run.text:
                    continue

                # 保存字体格式
                font_info = {
                    'name': getattr(run.font, 'name', None),
                    'size': getattr(run.font, 'size', None),
                    'bold': getattr(run.font, 'bold', None),
                    'italic': getattr(run.font, 'italic', None),
                    'underline': getattr(run.font, 'underline', None),
                    'color': comprehensive_get_color_info(run.font)
                }

                # 翻译文本
                original_text = run.text
                translated_text = translate_text(original_text) if should_translate(original_text) else original_text

                translated_runs.append({
                    'text': translated_text,
                    'font': font_info
                })

            translated_paragraphs.append({
                'runs': translated_runs,
                'format': para_format
            })

        # 3. 非破坏性更新：直接更新现有的runs，而不是清空重建
        for para_idx, para_data in enumerate(translated_paragraphs):
            if para_idx >= len(text_frame.paragraphs):
                # 如果需要更多段落，才添加新段落
                paragraph = text_frame.add_paragraph()
            else:
                paragraph = text_frame.paragraphs[para_idx]

            # 恢复段落格式
            set_paragraph_format(paragraph, para_data['format'])

            # 更新或创建runs
            run_data_list = para_data['runs']
            existing_runs = list(paragraph.runs)

            for run_idx, run_data in enumerate(run_data_list):
                if run_idx < len(existing_runs):
                    # 更新现有run
                    run = existing_runs[run_idx]
                else:
                    # 创建新run
                    run = paragraph.add_run()

                # 更新文本
                run.text = run_data['text']

                # 恢复字体格式
                font_info = run_data['font']
                try:
                    if font_info.get('name'):
                        run.font.name = font_info['name']
                    if font_info.get('size'):
                        run.font.size = font_info['size']
                    if font_info.get('bold') is not None:
                        run.font.bold = font_info['bold']
                    if font_info.get('italic') is not None:
                        run.font.italic = font_info['italic']
                    if font_info.get('underline') is not None:
                        run.font.underline = font_info['underline']

                    # 设置颜色（最重要的改进）
                    comprehensive_set_color_info(run.font, font_info.get('color'))

                except Exception as e:
                    logger.debug(f"Error applying font formatting to run: {e}")

            # 删除多余的runs（如果翻译后run数量减少）
            while len(existing_runs) > len(run_data_list):
                run_to_remove = existing_runs.pop()
                # 注意：python-pptx可能不支持直接删除run，这里先清空文本
                try:
                    run_to_remove.text = ""
                except:
                    pass

        # 4. 恢复文本框级别格式
        set_text_frame_format(text_frame, frame_format)

        return True

    except Exception as e:
        logger.error(f"Error in non_destructive_translate_text_frame: {e}")
        return False


# ====== 形状处理函数（保持不变）======
def is_shape_with_text(shape):
    """检测形状是否包含文本"""
    try:
        return (hasattr(shape, 'text_frame') and
                shape.text_frame is not None and
                hasattr(shape.text_frame, 'text') and
                shape.text_frame.text.strip())
    except:
        return False


def get_shape_info(shape):
    """获取形状的详细信息"""
    info = {
        'has_text': False,
        'shape_type': None,
        'is_group': False,
        'is_table': False,
        'is_chart': False,
        'text': ''
    }

    try:
        info['shape_type'] = shape.shape_type

        if hasattr(shape, 'shapes'):  # 组合对象
            info['is_group'] = True

        elif shape.shape_type == MSO_SHAPE_TYPE.TABLE:
            info['is_table'] = True
            # 额外验证是否真的有table属性
            if not hasattr(shape, 'table'):
                info['is_table'] = False

        elif shape.shape_type == MSO_SHAPE_TYPE.CHART:
            info['is_chart'] = True

        if is_shape_with_text(shape):
            info['has_text'] = True
            info['text'] = shape.text_frame.text

    except Exception as e:
        logger.debug(f"Error getting shape info: {e}")

    return info


def process_group_shape(group_shape):
    """处理组合形状"""
    processed_count = 0
    try:
        if hasattr(group_shape, 'shapes'):
            for sub_shape in group_shape.shapes:
                if is_shape_with_text(sub_shape):
                    print(f"  处理组合中的子形状文本...")
                    if non_destructive_translate_text_frame(sub_shape.text_frame):
                        processed_count += 1
                # 递归处理嵌套组合
                elif hasattr(sub_shape, 'shapes'):
                    processed_count += process_group_shape(sub_shape)
    except Exception as e:
        logger.error(f"Error processing group shape: {e}")

    return processed_count


def process_table_shape(table_shape):
    """处理表格形状"""
    processed_count = 0
    try:
        # 先检查是否真的有table属性
        if hasattr(table_shape, 'table') and table_shape.table is not None:
            for row_idx, row in enumerate(table_shape.table.rows):
                for col_idx, cell in enumerate(row.cells):
                    if cell.text.strip():
                        print(f"  处理表格单元格 ({row_idx + 1},{col_idx + 1})...")
                        if non_destructive_translate_text_frame(cell.text_frame):
                            processed_count += 1
        else:
            logger.warning("Shape claimed to be table but has no table attribute")
    except Exception as e:
        logger.error(f"Error processing table shape: {e}")

    return processed_count


def process_single_shape(shape):
    """处理单个形状"""
    try:
        shape_info = get_shape_info(shape)

        print(f"  检测到形状类型: {shape_info['shape_type']}")

        if shape_info['is_group']:
            print("  处理组合形状...")
            return process_group_shape(shape)

        elif shape_info['is_table']:
            print("  处理表格形状...")
            return process_table_shape(shape)

        elif shape_info['has_text']:
            print(f"  处理文本形状...")
            if non_destructive_translate_text_frame(shape.text_frame):
                return 1

    except Exception as e:
        logger.error(f"Error processing shape: {e}")
        print(f"  处理形状时出错: {str(e)}")

    return 0

def validate_ppt_file(file_path):
    """验证PPT文件是否可以正常打开"""
    try:
        prs = Presentation(file_path)
        print(f"PPT文件验证成功，包含 {len(prs.slides)} 页")
        return True, len(prs.slides)
    except Exception as e:
        print(f"PPT文件验证失败: {e}")
        return False, 0


def translate_ppt(input_path, output_path):
    """主翻译函数"""

    # 1. 验证输入文件
    print("验证输入文件...")
    valid, slide_count = validate_ppt_file(input_path)
    if not valid:
        raise Exception("输入的PPT文件无法正常打开")

    # 2. 创建备份（可选）

    try:
        print(f"开始翻译PPT文件，共 {slide_count} 页...")
        prs = Presentation(input_path)

        total_processed = 0

        for slide_idx, slide in enumerate(prs.slides):
            print(f"\n正在处理第 {slide_idx + 1}/{slide_count} 页...")

            slide_processed = 0
            shape_count = len(slide.shapes)
            print(f"  发现 {shape_count} 个形状")

            # 遍历所有形状
            for shape_idx, shape in enumerate(slide.shapes):
                try:
                    print(f"  正在处理形状 {shape_idx + 1}/{shape_count}...")
                    processed = process_single_shape(shape)
                    slide_processed += processed

                    # 添加小延迟避免API限制
                    if processed > 0:
                        time.sleep(0.5)

                except Exception as e:
                    print(f"  处理形状 {shape_idx + 1} 时出错：{str(e)}")
                    logger.error(f"Error processing shape {shape_idx + 1} on slide {slide_idx + 1}: {str(e)}")
                    continue

            total_processed += slide_processed
            print(f"  第 {slide_idx + 1} 页完成，处理了 {slide_processed} 个文本元素")

        # 3. 保存文件
        print(f"\n正在保存翻译后的PPT文件: {output_path}")
        prs.save(output_path)

        # 4. 验证输出文件
        print("验证输出文件...")
        output_valid, _ = validate_ppt_file(output_path)
        if not output_valid:
            print("警告：翻译后的PPT文件可能有问题，但已保存")

        print(f"翻译完成！总共处理了 {total_processed} 个文本元素")
        print(f"输出文件: {output_path}")

        return True, total_processed

    except Exception as e:
        print(f"翻译过程中出现错误: {e}")
        raise e


# ====== 主入口 ======
if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    try:
        input_ppt = input("请输入要翻译的 PPT 文件路径: ").strip()
        output_ppt = input("请输入翻译后 PPT 保存路径: ").strip()

        if not os.path.exists(input_ppt):
            raise FileNotFoundError(f"输入文件不存在: {input_ppt}")

        # 显示配置摘要
        print(f"\n=== 配置摘要 ===")
        print(f"源语言: {source_lang if source_lang else '自动检测'}")
        print(f"目标语言: {target_lang}")
        print(f"术语表: {len(glossaries)} 个")
        print(f"使用默认字体: {'是' if DEFAULT_FONT_CONFIG else '否'}")

        if DEFAULT_FONT_CONFIG:
            print(f"  - 字体: {DEFAULT_FONT_CONFIG['name']}")
            print(f"  - 大小: {DEFAULT_FONT_CONFIG['size'].pt}pt")
            print(
                f"  - 颜色: RGB({DEFAULT_FONT_CONFIG['color'].r}, {DEFAULT_FONT_CONFIG['color'].g}, {DEFAULT_FONT_CONFIG['color'].b})")
        print("================\n")

        # 显示加载的术语表摘要
        if glossaries:
            print(f"=== 术语表详情 ===")
            for glossary in glossaries:
                print(f"术语表: {glossary.name}, 术语数: {len(glossary.entries)}")
            print("==================\n")

        success, processed_count = translate_ppt(input_ppt, output_ppt)

        print(json.dumps({
            "success": True,
            "msg": "翻译完成",
            "output": os.path.abspath(output_ppt),
            "processed_count": processed_count,
            "glossaries_loaded": len(glossaries),
            "default_font_used": DEFAULT_FONT_CONFIG is not None,
            "improvements": [
                "非破坏性更新 - 保持原有结构",
                "完整颜色支持 - RGB/主题色/继承色",
                "段落格式保持 - 对齐/间距/层级",
                "文本框格式保持 - 边距/垂直对齐"
            ]
        }, ensure_ascii=False))

    except Exception as e:
        logger.error(f"Main execution error: {str(e)}")
        print(json.dumps({
            "success": False,
            "msg": str(e),
            "output": "",
            "processed_count": 0,
            "glossaries_loaded": 0,
            "backup_created": False,
            "default_font_used": False
        }, ensure_ascii=False))